package SGEngine

import (
	"fmt"
	"github.com/gl"
	"image"
	"image/draw"
	_ "image/jpeg"
	_ "image/png"
	"os"
)

var ACTextureMgr ACTextureMgr_

type ACTextureMgr_ struct {
	Textures map[string]*ACTexture
}

func init() {
	ACTextureMgr.Textures = make(map[string]*ACTexture)
}

type ACTexture struct {
	Img   *image.NRGBA
	TexID gl.Texture
}

func (a *ACTextureMgr_) LoadTexture(filename string) *ACTexture {

	if v, ok := a.Textures[filename]; ok == true {

		return v
	}

	f, err := os.Open(filename)

	CheckErr(err)
	Pimage, str, err := image.Decode(f)
	if err != nil {
		fmt.Println(str)
	}
	RGBAimg := image.NewNRGBA(Pimage.Bounds())
	switch str {
	case "jpeg":
		draw.Draw(RGBAimg, Pimage.Bounds(), Pimage, Pimage.Bounds().Min, draw.Src)
	case "png":
		RGBAimg = Pimage.(*image.NRGBA)
	default:
		fmt.Println("image format err")
	}

	imgWidth, imgHeight := RGBAimg.Bounds().Dx(), RGBAimg.Bounds().Dy()
	data := make([]byte, imgWidth*imgHeight*4)
	lineLen := imgWidth * 4
	dest := len(data) - lineLen
	for src := 0; src < len(RGBAimg.Pix); src += RGBAimg.Stride {
		copy(data[dest:dest+lineLen], RGBAimg.Pix[src:src+RGBAimg.Stride])
		dest -= lineLen
	}

	TexId := gl.GenTexture()
	TexId.Bind(gl.TEXTURE_2D)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	gl.TexImage2D(gl.TEXTURE_2D, 0, 4, imgWidth, imgHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
	RT := &ACTexture{RGBAimg, TexId}
	a.Textures[filename] = RT
	return RT
}

func (a *ACTextureMgr_) LoadTextureByNRGBA(RGBAimg *image.NRGBA, key string) *ACTexture {
	imgWidth, imgHeight := RGBAimg.Bounds().Dx(), RGBAimg.Bounds().Dy()
	data := make([]byte, imgWidth*imgHeight*4)
	lineLen := imgWidth * 4
	dest := len(data) - lineLen
	for src := 0; src < len(RGBAimg.Pix); src += RGBAimg.Stride {
		copy(data[dest:dest+lineLen], RGBAimg.Pix[src:src+RGBAimg.Stride])
		dest -= lineLen
	}

	TexId := gl.GenTexture()
	TexId.Bind(gl.TEXTURE_2D)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	gl.TexImage2D(gl.TEXTURE_2D, 0, 4, imgWidth, imgHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
	RT := &ACTexture{RGBAimg, TexId}
	a.Textures[key] = RT
	return RT
}

//////////////////

type ACImage struct {
	Node
	VBufferID   gl.Buffer
	TexBufferID gl.Buffer
	Tex         *ACTexture
	MProgram    *Program
	MColor      Color4
}

func NewACImage(filename string) *ACImage {
	RACImage := new(ACImage)
	RACImage.Node = DefaultNode()
	RACImage.Tex = ACTextureMgr.LoadTexture(filename)
	RACImage.GetNode().NodeRender = RACImage
	RACImage.VBufferID = ACBufferMgr.GetVertexBuffer(BUFFER_Quad)
	RACImage.TexBufferID = ACBufferMgr.GetTexBuffer(BUFFER_Quad)
	RACImage.GetNode().SetSize(float64(RACImage.Tex.Img.Bounds().Dx()), float64(RACImage.Tex.Img.Bounds().Dy()), 1)
	RACImage.MProgram = ACProgramMgr.GetProgram(PROGRAM_IMG)
	uniformTexture := RACImage.MProgram.ProgramObject.GetUniformLocation("s_texture")
	RACImage.MColor = NewColor4(1, 1, 1, 1)
	uniformTexture.Uniform1i(0)
	RACImage.MProgram.ProgramObject.GetUniformLocation("inColor").Uniform4f(1, 1, 1, 1)
	return RACImage
}
func (q *ACImage) Render() {
	gl.Enable(gl.ALPHA_TEST)
	gl.AlphaFunc(gl.GREATER, 0)

	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	//gl.ActiveTexture(gl.TEXTURE0)
	q.Tex.TexID.Bind(gl.TEXTURE_2D)
	q.MProgram.ProgramObject.Use()
	q.MProgram.ProgramObject.GetUniformLocation("inColor").Uniform4f(q.MColor.R, q.MColor.G, q.MColor.B, q.MColor.A)
	q.VBufferID.Bind(gl.ARRAY_BUFFER)
	q.MProgram.ProgramObject.GetAttribLocation("vPosition").AttribPointer(3, gl.FLOAT, false, 0, nil)
	q.MProgram.ProgramObject.GetAttribLocation("vPosition").EnableArray()
	q.TexBufferID.Bind(gl.ARRAY_BUFFER)
	q.MProgram.ProgramObject.GetAttribLocation("a_texCoord").AttribPointer(2, gl.FLOAT, false, 0, nil)
	q.MProgram.ProgramObject.GetAttribLocation("a_texCoord").EnableArray()
	gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
	q.VBufferID.Unbind(gl.ARRAY_BUFFER)
	q.TexBufferID.Unbind(gl.ARRAY_BUFFER)
	gl.Disable(gl.BLEND)
	//q.Tex.TexID.Unbind(gl.TEXTURE_2D)
}
